home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/time.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <errno.h>
- #include <malloc.h>
- #include <bstring.h>
-
- #include <X11/Intrinsic.h>
- #include <Xm/Xm.h>
- #include <Xm/List.h>
- #include <GL/GLwDrawA.h>
-
- #include "vroom.h"
- #include "server.h"
- #include "client.h"
- #include "track.h"
- #include "ogl.h"
- #include "solo.h"
- #include "multicast.h"
- #include "playmode.h"
- #include "sound.h"
- #include "messages.h"
-
- #define UPDATE_SPACING (1.0f) /* Time between status broadcasts */
- #define COURSE_ACK_DEADLINE (10.0f) /* Time for clients to ack course */
- #define TRIAL_SKILL_LEVEL (0.85f)
-
-
- typedef void (*ServerFunc)( void ) ;
-
- typedef struct _clientNode {
- long id ;
- long status ;
- long position ;
- float time ;
- float nextDeadLine ;
- struct _clientNode *next ;
- } ClientNode ;
-
- /* BEGIN PROTOTYPES -S server.c */
- static void addClient( long id ) ;
- static void addPlayer( long id ) ;
- static void addToClientListEnd( ClientNode *newClient ) ;
- static void autoFinish( void ) ;
- static void broadcastAckPacket( long id, long status, long data ) ;
- static void broadcastCoursePacket( outCoursePacket *packet ) ;
- static void broadcastNamePacket( long nPlayer ) ;
- static void broadcastRacePacket( void ) ;
- static void broadcastStatusPacket( void ) ;
- static int computeDistances( int laps ) ;
- static int createReadSocket( int port,
- struct sockaddr_in *addr ) ;
- static void fillCourseSelectorList( Widget courseSelector ) ;
- static ClientNode * findClient( long id ) ;
- static int findPlayer( long id ) ;
- static int initInputSpigot( int port ) ;
- static int loadTimes( int laps ) ;
- static int processInfoPacket( inInfoPacket *packet, int size ) ;
- static int processMsgPacket( inMsgPacket *packet, int size ) ;
- static int processNamePacket( inNamePacket *packet, int size ) ;
- static int processSpeedPacket( inSpeedPacket *packet, int size ) ;
- static void readCourses( void ) ;
- static void readInputSocket( void ) ;
- static void removeClient( long id ) ;
- static void removePlayer( long id ) ;
- static void resetClientDeadline( long id ) ;
- static void sendToNetwork( void *buf, int size ) ;
- static void serverNoOp( void ) ;
- static void serverPostRace( void ) ;
- static void serverPostTrial( void ) ;
- static void serverPreRace( void ) ;
- static void serverPreTrial( void ) ;
- static void serverRace( void ) ;
- static void serverTrial( void ) ;
- static void serverWaitForCourseAck( void ) ;
- static void serverWaitForCourseSel( void ) ;
- static void startTeamTrials( int courseNumber ) ;
- static void tallyCourseVotes( void ) ;
- static void updateClientList( void ) ;
- static void updateNames( void ) ;
- /* END PROTOTYPES -S server.c */
-
- Widget serverCourseLabel = NULL ;
-
- extern char *basename ;
- extern char teamPosition[] ;
- extern char *robotName[] ;
- extern char *myName ;
- extern int self ;
- extern int nCars ;
- extern int nTracks ;
- extern int nPlayers ;
- extern int raceLaps ;
- extern int isRobot[MAX_PLAYERS] ;
- extern int carsFinished ;
- extern int debugOn ;
- extern int startLastLap ;
- extern long myHostId ;
- extern float currentTime ;
- extern float startSoundTime ;
- extern float speedFactor ;
- extern Widget serverCourseForm ;
- extern Widget courseVoteForm ;
- extern Widget serverForm ;
- extern Widget mainOgl ;
- extern Car cars[] ;
- extern PlayerStruct player[] ;
- extern Sfx alertSfx ;
- extern Sfx lastlapSfx ;
- extern Sfx motorSfx ;
- extern Sfx startSfx ;
- extern Sfx toneSfx ;
-
- static int showRecord ;
- static ServerFunc serverFunc ;
- static CourseNode *courseList = NULL ;
- static ClientNode *clientList = NULL ;
- static int nClients = 0 ;
- static CourseNode *broadcastCourse = NULL ;
- static int nCourses = 0 ;
- static int *courseVotes ;
- static int inSock = -1 ;
- static struct sockaddr_in inAddr ;
- static int inLength ;
- static int outFd = -1 ;
- static struct sockaddr_in outAddr ;
- static char *servInputName = VROOM_SERVER_INPUT_SERVICE ;
- static char *servOutputName = VROOM_CLIENT_INPUT_SERVICE ;
- static float lastUpdateTime ;
- static float lastRaceTime ;
- static float endRaceTime ;
- static outStatusPacket statusPacket ;
- static float serverDeadLine ;
- static outCoursePacket *raceCoursePacket ;
- static outRacePacket racePacket ;
- static float startTime ;
- static float lastTime ;
-
-
-
- /*------------------------------------------------------------------------------
- * Initialize the server process.
- *----------------------------------------------------------------------------*/
- int
- initLocalServer(
- void
- )
- {
- int i ;
- int port ;
- Widget courseSelector ;
-
- busyCursor() ;
-
- port = getPort( servInputName, VROOM_SERVER_INPUT_PORT ) ;
-
- if( initInputSpigot( port ) < 0 )
- {
- fatalError( "Could not open socket for input." ) ;
- }
-
- /*
- * Get port number for broadcasting to clients.
- */
- port = getPort( servOutputName, VROOM_CLIENT_INPUT_PORT ) ;
-
- if( ( outFd = openMulticastSocket( &outAddr, port, getTtl(), 1,
- VROOM_GROUP, NULL, "w" ) ) < 0 )
- {
- fatalError( "Could not open multicast socket for output." ) ;
- }
-
- setWorkProc( VROOM_WP_RUN_SERVER, 1 ) ;
- serverFunc = serverNoOp ;
-
- readCourses() ;
-
- statusPacket.type = SERVER_P_STATUS ;
- statusPacket.id = myHostId ;
- statusPacket.status = SERVER_ST_COURSE_SEL ;
- statusPacket.nPlayers = 0 ;
- nPlayers = 0 ;
-
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- statusPacket.playerId[i] = i ; ;
- isRobot[i] = 1 ;
- strncpy( cars[i].name, robotName[i], sizeof( cars[i].name ) ) ;
- }
-
- nClients = 0 ;
- addClient( myHostId ) ;
-
- /*
- * Show course selection chooser.
- */
- courseSelector = createServerCourseSelector( serverCourseForm ) ;
-
- updateServerCourseLabel( nPlayers ) ;
-
- fillCourseSelectorList( courseSelector ) ;
-
- createMessageArea() ;
-
- setAdminForm( serverCourseForm ) ;
-
- setServerForNextGame() ;
-
- unbusyCursor() ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Create a socket for reading.
- *----------------------------------------------------------------------------*/
- static int
- initInputSpigot(
- int port
- )
- {
- /*
- * Create a socket.
- */
- if( ( inSock = createReadSocket( port, &inAddr ) ) == -1 )
- {
- return( -1 ) ;
- }
-
- /*
- * Turn on non-blocking I/O on the socket.
- */
- if( fcntl( inSock, F_SETFL, FNDELAY ) < 0 )
- {
- perror( "fcntl F_SETFL, FNDELAY" ) ;
- return( -1 ) ;
- }
-
- inLength = sizeof( inAddr ) ;
-
- return( 0 ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Read input socket, check for new players.
- *----------------------------------------------------------------------------*/
- static void
- readInputSocket(
- void
- )
- {
- int cnt ;
- int st ;
- inputPacket ip ;
-
- while( 1 )
- {
- /*
- * Read from the socket.
- */
- cnt = recvfrom( inSock, (char *)&ip, sizeof( ip ), 0,
- &inAddr, &inLength ) ;
-
- /*
- * If no data was in the socket, cnt will be -1 and errno
- * will be set to EWOULDBLOCK. Otherwise, if data was there,
- * cnt will contain the size of the data packet.
- */
- if( cnt < 0 )
- {
- if( errno != EWOULDBLOCK )
- {
- fatalError( "recvfrom: %s",
- strerror( errno ) ) ;
- }
- else
- {
- updateClientList() ;
- return ;
- }
- }
-
- st = 0 ;
-
- switch( ip.base.type )
- {
- case CLIENT_P_SPEED :
- st = processSpeedPacket( &ip.speed, cnt ) ;
- break ;
-
- case CLIENT_P_INFO :
- st = processInfoPacket( &ip.info, cnt ) ;
- break ;
-
- case CLIENT_P_NAME :
- st = processNamePacket( &ip.name, cnt ) ;
- break ;
-
- case CLIENT_P_MESSAGE :
- st = processMsgPacket( &ip.msg, cnt ) ;
- break ;
-
- default :
- fprintf( stderr, "%s: unknown packet size "
- "received (%d)\n", basename, cnt ) ;
- break ;
- }
-
- if( st )
- {
- fprintf( stderr, "%s: bad client packet size received "
- "(%d bytes, type = 0x%08x)\n", basename, cnt,
- ip.base.type ) ;
- }
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Create a socket for players to connect to.
- *----------------------------------------------------------------------------*/
- static int
- createReadSocket(
- int port,
- struct sockaddr_in *addr
- )
- {
- int sock ;
- int on ;
-
- sock = socket( AF_INET, SOCK_DGRAM, 0 ) ;
- if( sock < 0 )
- {
- perror("opening stream socket");
- return( -1 ) ;
- }
-
- /*
- * Initialize socket data structure.
- */
- addr->sin_family = AF_INET ;
- addr->sin_addr.s_addr = INADDR_ANY ;
- addr->sin_port = htons( port ) ;
-
- /*
- * Allow multiple binds to the socket.
- */
- on = 1;
- if( setsockopt( sock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on) ) < 0 )
- {
- close( sock ) ;
- perror( "setsockopt REUSEPORT" ) ;
- return( -1 ) ;
- }
-
- /*
- * Bind socket data structure to this socket.
- */
- if( bind( sock, addr, sizeof( *addr ) ) < 0 )
- {
- perror( "binding stream socket" ) ;
- shutdown( sock, 0 ) ;
- close( sock ) ;
- return( -1 ) ;
- }
-
- return( sock ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Convert hostid to a name string.
- *----------------------------------------------------------------------------*/
- char *
- hostNameFromId(
- long id,
- int showIp
- )
- {
- struct in_addr sin ;
- struct hostent *hp ;
- static char buffer[256] ;
-
- sin.s_addr = id ;
- hp = gethostbyaddr( &sin, sizeof( sin ), AF_INET ) ;
- if( hp )
- {
- if( showIp )
- {
- sprintf( buffer, "%s (%s)", hp->h_name,
- inet_ntoa( sin ) ) ;
- }
- else
- {
- sprintf( buffer, "%s", hp->h_name ) ;
- }
- }
- else
- {
- sprintf( buffer, "%s", inet_ntoa( sin ) ) ;
- }
- return( buffer ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Add a client to the list and respond.
- *----------------------------------------------------------------------------*/
- static void
- addClient(
- long id
- )
- {
- ClientNode *client ;
-
- /*
- * First, make sure client is not already in list.
- */
- if( ( client = findClient( id ) ) == NULL )
- {
- client = (ClientNode *)malloc( sizeof( ClientNode ) ) ;
- if( client == NULL )
- {
- broadcastAckPacket( id, ACK_ST_FAIL, 0 ) ;
- return ;
- }
- /*
- * Add client as a player (and inform of player number).
- */
- else if( nClients < MAX_PLAYERS &&
- statusPacket.status == SERVER_ST_COURSE_SEL )
- {
- client->id = id ;
- client->status = ACK_ST_CANDIDATE ;
- client->position = nClients ;
- client->time = currentTime ;
- /*
- * Insert player clients at first of chain.
- */
- client->next = clientList ;
- clientList = client ;
- if( id == myHostId )
- {
- addPlayer( id ) ;
- strncpy( cars[self].name, myName,
- sizeof( cars[self].name ) ) ;
- }
- broadcastAckPacket( id, ACK_ST_CANDIDATE, nClients ) ;
- }
- else
- {
- broadcastAckPacket( id, ACK_ST_WAIT, nClients ) ;
- client->id = id ;
- client->status = ACK_ST_WAIT ;
- client->position = nClients ;
- client->time = currentTime ;
- client->next = NULL ;
- addToClientListEnd( client ) ;
- broadcastCourse = courseList ;
- }
- nClients++ ;
- }
- else
- {
- broadcastAckPacket( id, client->status, client->position ) ;
- }
-
- client->nextDeadLine = currentTime + CLIENT_TIMEOUT ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Remove a client from the list and inform.
- *----------------------------------------------------------------------------*/
- static void
- removeClient(
- long id
- )
- {
- ClientNode *client = clientList ;
- ClientNode *prev = NULL ;
-
- while( client && client->id != id )
- {
- prev = client ;
- client = client->next ;
- }
-
- if( client != NULL && client->id == id )
- {
- broadcastAckPacket( id, ACK_ST_DROP, nClients ) ;
-
- if( prev == NULL )
- {
- clientList = client->next ;
- }
- else
- {
- prev->next = client->next ;
- }
- free( client ) ;
- nClients-- ;
- broadcastAckPacket( id, ACK_ST_DROP, nClients ) ;
- broadcastStatusPacket() ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Add a client node to the end of the chain.
- *----------------------------------------------------------------------------*/
- static void
- addToClientListEnd(
- ClientNode *newClient
- )
- {
- ClientNode *client = clientList ;
-
- if( client == NULL )
- {
- clientList = newClient ;
- return ;
- }
-
- while( client->next != NULL )
- {
- client = client->next ;
- }
-
- client->next = newClient ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Broadcast an acknowledgement packet.
- *----------------------------------------------------------------------------*/
- static void
- broadcastAckPacket(
- long id,
- long status,
- long data
- )
- {
- outAckPacket ack ;
-
- ack.type = SERVER_P_ACK ;
- ack.id = myHostId ;
- ack.targetId = id ;
- ack.status = status ;
- ack.data = data ;
- sendToNetwork( &ack, sizeof( ack ) ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Broadcast a name packet.
- *----------------------------------------------------------------------------*/
- static void
- broadcastNamePacket(
- long nPlayer
- )
- {
- outNamePacket name ;
-
- name.type = SERVER_P_NAME ;
- name.id = myHostId ;
- name.nPlayer = nPlayer ;
- strncpy( name.name, cars[nPlayer].name, sizeof( name.name ) ) ;
- sendToNetwork( &name, sizeof( name ) ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Broadcast a message packet.
- *----------------------------------------------------------------------------*/
- void
- broadcastMsgPacket(
- long nPlayer,
- char *msg
- )
- {
- outMsgPacket packet ;
-
- packet.type = SERVER_P_MESSAGE ;
- packet.id = myHostId ;
- packet.nPlayer = nPlayer ;
- strncpy( packet.msg, msg, sizeof( packet.msg ) ) ;
- packet.msg[sizeof( packet.msg ) - 1] = '\0' ;
- sendToNetwork( &packet, sizeof( packet ) ) ;
- postNewMessage( nPlayer, msg ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Broadcast a course packet.
- *----------------------------------------------------------------------------*/
- static void
- broadcastCoursePacket(
- outCoursePacket *packet
- )
- {
- sendToNetwork( packet, sizeof( outCoursePacket ) ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Broadcast a status packet.
- *----------------------------------------------------------------------------*/
- static void
- broadcastStatusPacket(
- void
- )
- {
- sendToNetwork( &statusPacket, sizeof( outStatusPacket ) ) ;
- lastUpdateTime = currentTime ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Broadcast the race packet.
- *----------------------------------------------------------------------------*/
- static void
- broadcastRacePacket(
- void
- )
- {
- int i ;
-
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- racePacket.status[i] = cars[i].status ;
- racePacket.x[i] = player[i].x ;
- racePacket.y[i] = player[i].y ;
- racePacket.z[i] = player[i].z ;
- racePacket.thetaDeg[i] = player[i].thetaDeg ;
- racePacket.roll[i] = player[i].roll ;
- racePacket.headingDeg[i] = player[i].headingDeg ;
- racePacket.totalDis[i] = cars[i].totalDis ;
- racePacket.position[i] = player[i].place ;
- racePacket.desiredSpeed[i] = cars[i].desiredSpeed ;
- racePacket.lane[i] = cars[i].lane ;
- teamPosition[player[i].place - 1] = i ;
- }
- sendToNetwork( &racePacket, sizeof( outRacePacket ) ) ;
- lastRaceTime = currentTime ;
- /*
- * Clear bump bit (bump bit is used to signal collision sound on
- * clients -- need only do once per bump).
- */
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- cars[i].status &= ~CAR_BUMP ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Write a packet to the network.
- *----------------------------------------------------------------------------*/
- static void
- sendToNetwork(
- void *buf,
- int size
- )
- {
- int noCharsSent ;
-
- noCharsSent = sendto( outFd, buf, size, 0, &outAddr, sizeof(outAddr) ) ;
- if( noCharsSent < size )
- {
- fatalError( "multicast sendto: %s", strerror( errno ) ) ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * The server main loop.
- *----------------------------------------------------------------------------*/
- void
- serverRun(
- void
- )
- {
- serverFunc() ;
-
- /*
- * Check to send an update packet.
- */
- if( currentTime - lastUpdateTime >= UPDATE_SPACING )
- {
- broadcastStatusPacket() ;
- }
-
- /*
- * Check to broadcast course info.
- */
- if( broadcastCourse != NULL )
- {
- broadcastCoursePacket( broadcastCourse->packet ) ;
- broadcastCourse = broadcastCourse->next ;
- }
-
- /*
- * Read input from clients.
- */
- readInputSocket() ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Read in and store the race courses.
- *----------------------------------------------------------------------------*/
- static void
- readCourses(
- void
- )
- {
- int n = 0 ;
- CourseNode *course ;
-
- nCourses = readServerCourses( &courseList ) ;
-
- if( nCourses == 0 )
- {
- fatalError( "No race courses were found!" ) ;
- }
-
- courseVotes = myMalloc( nCourses * sizeof( int ) ) ;
-
- course = courseList ;
- while( course )
- {
- course->packet->type = SERVER_P_COURSE ;
- course->packet->id = myHostId ;
- course->packet->courseId = n ;
- n++ ;
- course = course->next ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Locate a client in the client node list by id.
- *----------------------------------------------------------------------------*/
- static ClientNode *
- findClient(
- long id
- )
- {
- ClientNode *client = clientList ;
-
- while( client != NULL && client->id != id )
- {
- client = client->next ;
- }
-
- return( client ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Add a player.
- *----------------------------------------------------------------------------*/
- static void
- addPlayer(
- long id
- )
- {
- int i ;
- int n ;
- ClientNode *client ;
- char msg[VROOM_MSGLEN] ;
-
- if( ( client = findClient( id ) ) == NULL ||
- client->status != ACK_ST_CANDIDATE )
- {
- printf( "%s tried to become player unsuccessfully\n",
- hostNameFromId( id, 0 ) ) ;
- return ;
- }
-
- client->status = ACK_ST_PLAYER ;
-
- nPlayers++ ;
- statusPacket.nPlayers = nPlayers ;
-
- /*
- * Add player in first computer spot.
- */
- n = -1 ;
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- if( isRobot[i] == 1 )
- {
- n = i ;
- break ;
- }
- }
-
- if( n == -1 )
- {
- fatalError( "Unforeseen error adding player." ) ;
- }
-
- statusPacket.playerId[n] = id ;
- statusPacket.selection[n] = -1 ;
- isRobot[n] = 0 ;
- broadcastCourse = courseList ;
- client->nextDeadLine = currentTime + CLIENT_TIMEOUT ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Remove a player.
- *----------------------------------------------------------------------------*/
- static void
- removePlayer(
- long id
- )
- {
- int i ;
- int n ;
- char str[VROOM_MSGLEN] ;
- ClientNode *client ;
-
- if( ( n = findPlayer( id ) ) == -1 )
- {
- return ;
- }
-
- if( ( client = findClient( id ) ) == NULL ||
- client->status != ACK_ST_PLAYER )
- {
- return ;
- }
-
- nPlayers-- ;
- updateServerCourseLabel( nPlayers ) ;
- statusPacket.nPlayers = nPlayers ;
- statusPacket.playerId[n] = n ;
- isRobot[n] = 1 ;
- sprintf( str, "%s left the game.", cars[n].name ) ;
- broadcastMsgPacket( -1, str ) ;
- strncpy( cars[n].name, robotName[n], sizeof( cars[n].name ) ) ;
- updateNames() ;
- broadcastStatusPacket() ;
- switch( statusPacket.status )
- {
- case SERVER_ST_COURSE_SEL :
- tallyCourseVotes() ;
- break ;
-
- case SERVER_ST_COURSE_ACK :
- case SERVER_ST_PRE_TRIAL :
- case SERVER_ST_TRIAL :
- case SERVER_ST_POST_TRIAL :
- case SERVER_ST_PRE_RACE :
- case SERVER_ST_RACE :
- case SERVER_ST_POST_RACE :
- setMessage( "Repaced %s with robot.\n",
- hostNameFromId( id, 0 ) ) ;
- break ;
- }
- sfxPlay( alertSfx ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Determine a port number from a service name.
- *----------------------------------------------------------------------------*/
- int
- getPort(
- char *servName,
- int defaultPort
- )
- {
- int port ;
- struct servent *serv ;
-
- /*
- * Get port number for listening to clients.
- */
- if( ( serv = getservbyname( servName, NULL ) ) == NULL )
- {
- port = defaultPort ;
- }
- else
- {
- port = serv->s_port ;
- }
-
- return( port ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Process a speed packet.
- *----------------------------------------------------------------------------*/
- static int
- processSpeedPacket(
- inSpeedPacket *packet,
- int size
- )
- {
- int n ;
-
- if( size != sizeof( inSpeedPacket ) )
- {
- return( -1 ) ;
- }
-
- n = packet->playerNumber ;
- if( packet->id == statusPacket.playerId[n] )
- {
- cars[n].desiredSpeed = packet->speed ;
- if( packet->steer != 0 )
- {
- cars[n].status &= ~CHANGE_LANES ;
- cars[n].status |= ( packet->steer & CHANGE_LANES ) ;
- }
- }
-
- return( 0 ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Process an info packet.
- *----------------------------------------------------------------------------*/
- static int
- processInfoPacket(
- inInfoPacket *packet,
- int size
- )
- {
- if( size != sizeof( inInfoPacket ) )
- {
- return( -1 ) ;
- }
-
- switch( packet->option )
- {
- case CLIENT_INFO_JOIN :
- addClient( packet->id ) ;
- break ;
-
- case CLIENT_INFO_ACCEPT :
- addPlayer( packet->id ) ;
- updateServerCourseLabel( nPlayers ) ;
- sfxPlay( alertSfx ) ;
- break ;
-
- case CLIENT_INFO_QUIT :
- removePlayer( packet->id ) ;
- removeClient( packet->id ) ;
- break ;
-
- case CLIENT_INFO_UPDATE :
- break ;
-
- case CLIENT_INFO_COURSE_SEL :
- clientChoseCourse( packet->id, packet->choice ) ;
- break ;
-
- case CLIENT_INFO_COURSE_ACK :
- clientAckCourse( packet->id ) ;
- break ;
-
- default :
- printf( "%s: unknown option (0x%08x) in info packet\n",
- basename, packet->option ) ;
- return( 0 ) ;
- break ;
- }
- resetClientDeadline( packet->id ) ;
-
- return( 0 ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Process a name packet from a client.
- *----------------------------------------------------------------------------*/
- static int
- processNamePacket(
- inNamePacket *packet,
- int size
- )
- {
- int n ;
-
- if( size != sizeof( inNamePacket ) )
- {
- return( -1 ) ;
- }
-
- if( ( n = findPlayer( packet->id ) ) != -1 )
- {
- strncpy( cars[n].name, packet->name, sizeof( cars[n].name ) ) ;
- updateNames() ;
- }
-
- resetClientDeadline( packet->id ) ;
-
- return( 0 ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Process a message packet from a client.
- *----------------------------------------------------------------------------*/
- static int
- processMsgPacket(
- inMsgPacket *packet,
- int size
- )
- {
- int n ;
-
- if( size != sizeof( inMsgPacket ) )
- {
- return( -1 ) ;
- }
-
- if( ( n = findPlayer( packet->id ) ) != -1 )
- {
- broadcastMsgPacket( n, packet->msg ) ;
- }
-
- resetClientDeadline( packet->id ) ;
-
- return( 0 ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Add local courses to the selection list.
- *----------------------------------------------------------------------------*/
- static void
- fillCourseSelectorList(
- Widget courseSelector
- )
- {
- CourseNode *course = courseList ;
-
- XmListDeleteAllItems( courseSelector ) ;
- while( course )
- {
- addCourseToSelectionList( courseSelector,
- course->packet->name ) ;
- course = course->next ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Client-called routine to build the course list.
- *----------------------------------------------------------------------------*/
- int
- addToCourseList(
- outCoursePacket *packet
- )
- {
- CourseNode *course ;
- CourseNode *newCourse ;
-
- /*
- * First check to see if course is already in list.
- */
- course = courseList ;
- while( course )
- {
- if( course->packet->courseId == packet->courseId )
- {
- return( 0 ) ;
- }
- course = course->next ;
- }
-
- newCourse = myMalloc( sizeof( CourseNode ) ) ;
- newCourse->packet = myMalloc( sizeof( outCoursePacket ) ) ;
- newCourse->next = NULL ;
- bcopy( packet, newCourse->packet, sizeof( outCoursePacket ) ) ;
-
- if( courseList == NULL )
- {
- courseList = newCourse ;
- }
- else
- {
- course = courseList ;
-
- while( course->next != NULL )
- {
- course = course->next ;
- }
-
- course->next = newCourse ;
- }
-
- nCourses++ ;
-
- return( 1 ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Clear the course list (free up memory).
- *----------------------------------------------------------------------------*/
- void
- clearCourseList(
- void
- )
- {
- CourseNode *course = courseList ;
- CourseNode *next ;
-
- while( course )
- {
- next = course->next ;
- free( course->packet ) ;
- free( course ) ;
- course = next ;
- }
-
- courseList = NULL ;
- nCourses = 0 ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Return the matching course in the list.
- *----------------------------------------------------------------------------*/
- outCoursePacket *
- findCourseInList(
- char *name
- )
- {
- CourseNode *course = courseList ;
-
- while( course )
- {
- if( !strcmp( name, course->packet->name ) )
- {
- return( course->packet ) ;
- }
- course = course->next ;
- }
-
- return( NULL ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Return the matching course in the list based on course id.
- *----------------------------------------------------------------------------*/
- outCoursePacket *
- findCourseInListById(
- long courseId
- )
- {
- CourseNode *course = courseList ;
-
- while( course )
- {
- if( course->packet->courseId == courseId )
- {
- return( course->packet ) ;
- }
- course = course->next ;
- }
-
- return( NULL ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Update the client list, checking for timeouts.
- *----------------------------------------------------------------------------*/
- static void
- updateClientList(
- void
- )
- {
- ClientNode *client ;
- ClientNode *prev ;
-
- if( clientList == NULL )
- {
- return ;
- }
-
- prev = NULL ;
- client = clientList ;
-
- while( client )
- {
- if( client->id != myHostId &&
- client->nextDeadLine < currentTime )
- {
- printf( "client %s didn't respond by deadline\n",
- hostNameFromId( client->id, 0 ) ) ;
- removePlayer( client->id ) ;
- removeClient( client->id ) ;
- }
- prev = client ;
- client = prev->next ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Return the index of a player given the id.
- *----------------------------------------------------------------------------*/
- static int
- findPlayer(
- long id
- )
- {
- int i ;
-
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- if( statusPacket.playerId[i] == id )
- {
- return( i ) ;
- }
- }
-
- return( -1 ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Handle a client choosing a course.
- *----------------------------------------------------------------------------*/
- void
- clientChoseCourse(
- long id,
- int choice
- )
- {
- int i ;
- int n ;
- char msg[MAX_COURSE_NAME+12] ;
- CourseNode *cn = courseList ;
-
- if( choice < 0 || choice >= nCourses )
- {
- broadcastAckPacket( id, ACK_ST_COURSE_VOTE, -1 ) ;
- return ;
- }
- else
- {
- broadcastAckPacket( id, ACK_ST_COURSE_VOTE, choice ) ;
- }
-
- if( ( n = findPlayer( id ) ) != -1 )
- {
- for( i = 0 ; i < choice ; i++ )
- {
- cn = cn->next ;
- }
- sprintf( msg, "I chose %s.", cn->packet->name ) ;
- broadcastMsgPacket( n, msg ) ;
- statusPacket.selection[n] = choice ;
- tallyCourseVotes() ;
- }
-
- if( id == myHostId )
- {
- busyCursor() ;
- setAdminForm( courseVoteForm ) ;
- unbusyCursor() ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Handle a client acknowledging a course selection.
- *----------------------------------------------------------------------------*/
- void
- clientAckCourse(
- long id
- )
- {
- int n ;
-
- if( ( n = findPlayer( id ) ) != -1 )
- {
- statusPacket.selection[n] = 1 ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Check if all players have voted for a course. If so, choose majority
- * winner or pick randomly if a tie among top vote getters.
- *----------------------------------------------------------------------------*/
- static void
- tallyCourseVotes(
- void
- )
- {
- int i ;
- int n ;
- int topVotes = 0 ;
- int topCourse = -1 ;
-
- for( i = 0 ; i < nCourses ; i++ )
- {
- courseVotes[i] = 0 ;
- }
-
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- if( isRobot[i] == 0 )
- {
- if( statusPacket.selection[i] != -1 )
- {
- n = ++(courseVotes[statusPacket.selection[i]]) ;
- if( n > topVotes )
- {
- topVotes = n ;
- }
- }
- else
- {
- return ;
- }
- }
- }
-
- n = 0 ;
- for( i = 0 ; i < nCourses ; i++ )
- {
- if( courseVotes[i] == topVotes )
- {
- n++ ;
- }
- }
-
- topCourse = (int)( n * (float)( rand() % 0x0ff ) / (float)( 0x100 ) ) ;
-
- /*
- * Safety check.
- */
- if( topCourse >= n )
- {
- topCourse = n - 1 ;
- }
-
- /*
- * Pick the course.
- */
- for( i = 0 ; i < nCourses ; i++ )
- {
- if( courseVotes[i] == topVotes )
- {
- n-- ;
- if( n == topCourse )
- {
- startTeamTrials( i ) ;
- return ;
- }
- }
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Initialize for starting time trials in team mode. Send status and wait for
- * all players to respond.
- *----------------------------------------------------------------------------*/
- static void
- startTeamTrials(
- int courseNumber
- )
- {
- int i ;
- CourseNode *cn = courseList ;
-
- for( i = 0 ; i < courseNumber ; i++ )
- {
- cn = cn->next ;
- }
-
- broadcastCoursePacket( cn->packet ) ;
- broadcastAckPacket( VROOM_ALL_PLAYERS, ACK_ST_COURSE_CHOSEN,
- courseNumber ) ;
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- statusPacket.selection[i] = 0 ;
- }
- statusPacket.selection[0] = 1 ;
- serverFunc = serverWaitForCourseAck ;
- serverDeadLine = currentTime + COURSE_ACK_DEADLINE ;
- statusPacket.status = SERVER_ST_COURSE_ACK ;
- broadcastStatusPacket() ;
-
- raceCoursePacket = cn->packet ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Do nothing while waiting for course selections.
- *----------------------------------------------------------------------------*/
- static void
- serverWaitForCourseSel(
- void
- )
- {
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Continue sending selected course info until all players acknowledge.
- *----------------------------------------------------------------------------*/
- static void
- serverWaitForCourseAck(
- void
- )
- {
- int i ;
- int n = -1 ;
- static float ackLastTime = 0.0f ;
-
- if( currentTime - ackLastTime > UPDATE_SPACING )
- {
- ackLastTime = currentTime ;
- broadcastAckPacket( VROOM_ALL_PLAYERS, ACK_ST_COURSE_CHOSEN,
- raceCoursePacket->courseId ) ;
- }
-
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- if( isRobot[i] == 0 && statusPacket.selection[i] == 0 )
- {
- n = i ;
- }
- }
-
- /*
- * All have acknowledged. Start the time trials.
- */
- if( n == -1 )
- {
- if( loadTrackFromPacket( raceCoursePacket ) != 0 )
- {
- fatalError( "Unexpected error creating chosen race"
- " course. Aborting execution." ) ;
- }
- serverFunc = serverPreTrial ;
- nCars = 1 ;
- initSoloCars( 1 ) ;
- setRobotChars( TRIAL_SKILL_LEVEL ) ;
- startTime = currentTime + 10.0f ;
- startSoundTime = startTime - 2.0f ;
- racePacket.type = SERVER_P_RACE ;
- racePacket.id = myHostId ;
- racePacket.mode = SERVER_ST_PRE_TRIAL ;
- statusPacket.status = SERVER_ST_PRE_TRIAL ;
- broadcastStatusPacket() ;
- racePacket.time = 5.0f ;
- startTimeTrials( 0 ) ;
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- racePacket.indTime[i] = 0.0f ;
- }
- }
- else
- {
- /*
- * If still here, not all players have acknowledged the course
- * selection. Drop 'em.
- */
- if( currentTime > serverDeadLine )
- {
- printf( "player %d (%s) did not acknowledge the "
- "course in time.\n", n,
- hostNameFromId( statusPacket.playerId[n], 0 ) );
- removePlayer( statusPacket.playerId[n] ) ;
- }
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Main loop during pre-trial.
- *----------------------------------------------------------------------------*/
- static void
- serverPreTrial(
- void
- )
- {
- int i ;
-
- racePacket.time = startTime - currentTime ;
- sfxPlayPitch( motorSfx, 0.5f * cars[self].desiredSpeed * speedFactor ) ;
- if( racePacket.time <= 0.0f )
- {
- sfxPlay( startSfx ) ;
- sfxPlayPitch( motorSfx, cars[self].desiredSpeed *
- speedFactor ) ;
- serverFunc = serverTrial ;
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- cars[i].startLapTime = currentTime ;
- cars[i].finishTime = 0.0f ;
- cars[i].totalDis = 0.0f ;
- }
- carsFinished = 0 ;
- startTime = currentTime + racePacket.time ;
- lastTime = currentTime ;
- racePacket.time = 0.0f ;
- setMessage( "Best of %d laps is used to qualify.",
- VROOM_TRIAL_LAPS ) ;
- racePacket.mode = SERVER_ST_TRIAL ;
- statusPacket.status = SERVER_ST_TRIAL ;
- broadcastStatusPacket() ;
- }
- else if( currentTime > startSoundTime )
- {
- sfxPlay( toneSfx ) ;
- startSoundTime += 1.0f ;
- }
-
- broadcastRacePacket() ;
-
- drawIt( self ) ;
- drawPreTrialOverlay( racePacket.time, teamPosition, 1, 0 ) ;
- GLwDrawingAreaSwapBuffers( mainOgl ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Empty function to hold place.
- *----------------------------------------------------------------------------*/
- static void
- serverNoOp(
- void
- )
- {
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Run the time trials.
- *----------------------------------------------------------------------------*/
- static void
- serverTrial(
- void
- )
- {
- int i ;
- float dTime ;
-
- dTime = currentTime - lastTime ;
- lastTime = currentTime ;
-
- racePacket.time = currentTime - startTime ;
-
- doAllCars( dTime, VROOM_TRIAL_LAPS, 1 ) ;
- computeDistances( VROOM_TRIAL_LAPS ) ;
- checkCarFinishes( VROOM_TRIAL_LAPS, racePacket.indTime, 1 ) ;
- if( cars[self].status & CAR_FINISHED )
- {
- serverFunc = serverPostTrial ;
- racePacket.mode = SERVER_ST_POST_TRIAL ;
- statusPacket.status = SERVER_ST_POST_TRIAL ;
- broadcastStatusPacket() ;
- endRaceTime = currentTime + 3.0f ;
- setMessage( "Waiting for all players to qualify.\n" ) ;
- sfxDisable( motorSfx ) ;
- stopSkid( cars+self ) ;
- }
- broadcastRacePacket() ;
- drawIt( self ) ;
- drawTrialOverlay( racePacket.indTime[self], teamPosition ) ;
- GLwDrawingAreaSwapBuffers( mainOgl ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * After the time trials, wait for all robots to finish at least one lap.
- *----------------------------------------------------------------------------*/
- static void
- serverPostTrial(
- void
- )
- {
- int i ;
- int l ;
- float dTime ;
- float skill ;
- float avgRobotTime ;
- float avgHumanTime ;
- float bestRobotTime = 1e30 ;
- float nextBestRobotTime = 1e30 ;
-
- racePacket.time = currentTime - startTime ;
-
- if( carsFinished == MAX_PLAYERS && currentTime > endRaceTime )
- {
- placeCarsForStart() ;
- avgRobotTime = 0.0f ;
- avgHumanTime = 0.0f ;
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- cars[i].lap = -1 ;
- cars[i].totalDis = cars[i].s - 1.0f ;
- cars[i].lapDis = cars[i].totalDis ;
- cars[i].status = 0 ;
- if( isRobot[i] )
- {
- avgRobotTime += cars[i].bestLapTime ;
- if( cars[i].bestLapTime < bestRobotTime )
- {
- nextBestRobotTime = bestRobotTime ;
- bestRobotTime = cars[i].bestLapTime ;
- }
- else if( cars[i].bestLapTime <
- nextBestRobotTime )
- {
- nextBestRobotTime = cars[i].bestLapTime;
- }
- }
- else
- {
- avgHumanTime += cars[i].bestLapTime ;
- }
- }
- avgHumanTime /= (float)nPlayers ;
- /*
- * Try to adjust robot skill factors based on average
- * qualification times of human players.
- */
- if( nPlayers < MAX_PLAYERS )
- {
- if( nextBestRobotTime < avgHumanTime )
- {
- skill = ( 1.0f - 0.02f * avgHumanTime /
- nextBestRobotTime ) *
- TRIAL_SKILL_LEVEL ;
- }
- else
- {
- skill = 0.20f * ( 1.0f - TRIAL_SKILL_LEVEL ) *
- nextBestRobotTime / avgHumanTime +
- TRIAL_SKILL_LEVEL ;
- }
- skill = MINFUNC( skill, 1.0f ) ;
- setRobotChars( skill ) ;
- }
- serverFunc = serverPreRace ;
- sfxEnable( motorSfx ) ;
- i = teamPosition[0] ;
- l = 0 ;
- for( i = 1 ; i < MAX_PLAYERS ; i++ )
- {
- if( cars[i].bestLapTime < cars[l].bestLapTime )
- {
- l = i ;
- }
- }
- showRecord = checkLapRecord( cars[l].bestLapTime,
- cars[l].name, 1 ) ;
- racePacket.mode = SERVER_ST_PRE_RACE ;
- statusPacket.status = SERVER_ST_PRE_RACE ;
- nCars = MAX_PLAYERS ;
- startTime = currentTime + 10.0f ;
- startSoundTime = startTime - 2.0f ;
- broadcastStatusPacket() ;
- }
- else
- {
- dTime = currentTime - lastTime ;
- lastTime = currentTime ;
- doAllCars( dTime, VROOM_TRIAL_LAPS, 1 ) ;
- i = computeDistances( VROOM_TRIAL_LAPS ) ;
- /*
- * Check if all human players have finished.
- */
- l = 0 ;
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- if( !isRobot[i] &&
- ( cars[i].status & CAR_FINISHED ) != 0 )
- {
- l++ ;
- }
- }
- if( l != nPlayers )
- {
- endRaceTime += dTime ;
- }
- checkCarFinishes( VROOM_TRIAL_LAPS, racePacket.indTime, 1 ) ;
- /*
- * Go ahead and end if computer cars have finished at least
- * one lap.
- */
- if( l == nPlayers && currentTime - endRaceTime > 2.0f )
- {
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- if( isRobot[i] && cars[i].lap > 0 &&
- ( cars[i].status & CAR_FINISHED ) == 0 )
- {
- autoFinishCar( i, 0.0f ) ;
- }
- }
- }
- drawIt( self ) ;
- drawPostTrialOverlay( racePacket.indTime[self], teamPosition ) ;
- GLwDrawingAreaSwapBuffers( mainOgl ) ;
- }
- broadcastRacePacket() ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Main loop for before the race.
- *----------------------------------------------------------------------------*/
- static void
- serverPreRace(
- void
- )
- {
- int i ;
- float dTime ;
-
- racePacket.time = startTime - currentTime ;
- sfxPlayPitch( motorSfx, 0.5f * cars[self].desiredSpeed * speedFactor ) ;
- if( racePacket.time <= 0.0f )
- {
- sfxPlay( startSfx ) ;
- sfxPlayPitch( motorSfx, cars[self].desiredSpeed *
- speedFactor ) ;
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- cars[i].startLapTime = currentTime ;
- cars[i].finishTime = 0.0f ;
- cars[i].totalDis = 0.0f ;
- }
- carsFinished = 0 ;
- startTime = currentTime + racePacket.time ;
- lastTime = currentTime ;
- racePacket.time = 0.0f ;
- setMessage( "May the best driver win." ) ;
- serverFunc = serverRace ;
- startLastLap = 0 ;
- racePacket.mode = SERVER_ST_RACE ;
- statusPacket.status = SERVER_ST_RACE ;
- broadcastStatusPacket() ;
- }
- else if( currentTime > startSoundTime )
- {
- sfxPlay( toneSfx ) ;
- startSoundTime += 1.0f ;
- }
- broadcastRacePacket() ;
- drawIt( 0 ) ;
- drawPreTrialOverlay( racePacket.time, teamPosition, 0, showRecord ) ;
- GLwDrawingAreaSwapBuffers( mainOgl ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Main loop for race.
- *----------------------------------------------------------------------------*/
- static void
- serverRace(
- void
- )
- {
- float dTime ;
- int dLaps ;
- int n ;
-
- racePacket.time = currentTime - startTime ;
- dTime = currentTime - lastTime ;
- lastTime = currentTime ;
-
- doAllCars( dTime, raceLaps, 0 ) ;
- computePositions( teamPosition, raceLaps ) ;
- checkCarFinishes( raceLaps, racePacket.indTime, 0 ) ;
- autoFinish() ;
- loadTimes( raceLaps ) ;
- if( cars[self].status & CAR_FINISHED )
- {
- sfxDisable( motorSfx ) ;
- stopSkid( cars+self ) ;
- serverFunc = serverPostRace ;
- showFinishMessage() ;
- racePacket.mode = SERVER_ST_POST_RACE ;
- statusPacket.status = SERVER_ST_POST_RACE ;
- broadcastStatusPacket() ;
- endRaceTime = currentTime + 3.0f ;
- }
- else if( cars[self].lap == raceLaps - 1 && startLastLap == 0 )
- {
- startLastLap = 1 ;
- sfxPlay( lastlapSfx ) ;
- }
- broadcastRacePacket() ;
- drawIt( 0 ) ;
- if( player[self].place == 1 )
- {
- dLaps = (int)( cars[self].totalDis -
- cars[teamPosition[1]].totalDis ) / nTracks ;
- drawRaceOverlay( racePacket.time, raceLaps - cars[self].lap - 1,
- dLaps, 1, teamPosition ) ;
- }
- else
- {
- n = teamPosition[0] ;
- if( cars[n].status & CAR_FINISHED )
- {
- dLaps = raceLaps - cars[self].lap - 1 ;
- }
- else
- {
- dLaps = (int)( cars[n].totalDis -
- cars[self].totalDis ) / nTracks ;
- }
- drawRaceOverlay( racePacket.time, raceLaps - cars[self].lap - 1,
- dLaps, 0, teamPosition ) ;
- }
- GLwDrawingAreaSwapBuffers( mainOgl ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Main loop for after race.
- *----------------------------------------------------------------------------*/
- static void
- serverPostRace(
- void
- )
- {
- int i ;
- int st ;
- float d ;
- float dTime ;
-
- racePacket.time = currentTime - startTime ;
- if( carsFinished == MAX_PLAYERS && currentTime > endRaceTime )
- {
- serverFunc = serverNoOp ;
- racePacket.mode = SERVER_ST_RESULTS ;
- statusPacket.status = SERVER_ST_RESULTS ;
- broadcastStatusPacket() ;
- nCars = 1 ;
- showTeamResults( teamPosition ) ;
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- statusPacket.selection[i] = -1 ;
- }
- }
- else
- {
- autoFinish() ;
- dTime = currentTime - lastTime ;
- if( carsFinished != MAX_PLAYERS )
- {
- endRaceTime += dTime ;
- }
- lastTime = currentTime ;
- doAllCars( dTime, raceLaps, 0 ) ;
- computePositions( teamPosition, raceLaps ) ;
- checkCarFinishes( raceLaps, racePacket.indTime, 0 ) ;
- loadTimes( raceLaps ) ;
- broadcastRacePacket() ;
- drawIt( 0 ) ;
- drawPostRaceOverlay( racePacket.indTime[self], racePacket.time,
- teamPosition ) ;
- GLwDrawingAreaSwapBuffers( mainOgl ) ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Compute the lap and total distances during trial runs.
- *----------------------------------------------------------------------------*/
- static int
- computeDistances(
- int laps
- )
- {
- int i ;
- int finished = 0 ;
-
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- cars[i].lapDis = (float)( ( cars[i].track->number +
- nTracks - 1 ) % nTracks ) + cars[i].s ;
- cars[i].totalDis = cars[i].lapDis + nTracks * cars[i].lap ;
- if( ( cars[i].status & CAR_FINISHED ) == 0 )
- {
- racePacket.indTime[i] = currentTime -
- cars[i].startLapTime ;
- }
- else
- {
- finished++ ;
- }
- }
-
- return( finished ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Compute the times for individual cars during race.
- *----------------------------------------------------------------------------*/
- static int
- loadTimes(
- int laps
- )
- {
- int i ;
- int finished = 0 ;
-
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- if( ( cars[i].status & CAR_FINISHED ) == 0 )
- {
- racePacket.indTime[i] = currentTime - startTime ;
- }
- if( isRobot[i] == 0 && cars[i].lap >= laps )
- {
- finished++ ;
- }
- }
-
- return( finished ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Exit the server after notifying players.
- *----------------------------------------------------------------------------*/
- void
- closeServer(
- void
- )
- {
- statusPacket.status = SERVER_ST_QUIT ;
- broadcastStatusPacket() ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Reset the timeout deadline on a client.
- *----------------------------------------------------------------------------*/
- static void
- resetClientDeadline(
- long id
- )
- {
- ClientNode *client ;
-
- if( ( client = findClient( id ) ) != NULL )
- {
- client->nextDeadLine = currentTime + CLIENT_TIMEOUT ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * (Re)set server for next game.
- *----------------------------------------------------------------------------*/
- void
- setServerForNextGame(
- void
- )
- {
- int i ;
-
- serverFunc = serverWaitForCourseSel ;
- statusPacket.status = SERVER_ST_COURSE_SEL ;
- broadcastStatusPacket() ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Set the message displayed in the server course selection window.
- *----------------------------------------------------------------------------*/
- void
- setServerCourseLabel(
- char *fmt,
- ...
- )
- {
- va_list vargs ;
- int n ;
- Arg arg[1] ;
- XmString str ;
- char msg[1024] ;
-
- va_start( vargs, fmt ) ;
- if( serverCourseLabel != NULL )
- {
- vsprintf( msg, fmt, vargs ) ;
-
- str = XmStringCreateLtoR( msg, XmFONTLIST_DEFAULT_TAG ) ;
- n = 0 ;
- XtSetArg( arg[n], XmNlabelString, str ) ; n++ ;
- XtSetValues( serverCourseLabel, arg, n ) ;
- XmStringFree( str ) ;
- }
- va_end( vargs ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Update the server course label as players come and go.
- *----------------------------------------------------------------------------*/
- void
- updateServerCourseLabel(
- int np
- )
- {
- if( np == 1 )
- {
- setServerCourseLabel(
- "You are the only player. Selecting a\n"
- "course now will start the game immediately." ) ;
- }
- else
- {
- setServerCourseLabel(
- "There are now %d players. Vote on a course.\n"
- "The race will begin when all players have voted\n"
- "using the course with the most votes.", np ) ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Broadcast all of the human player names.
- *----------------------------------------------------------------------------*/
- static void
- updateNames(
- void
- )
- {
- int i ;
-
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- broadcastNamePacket( i ) ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Check for port number entries in the service listing.
- *----------------------------------------------------------------------------*/
- void
- checkPorts(
- void
- )
- {
- int port ;
- struct servent *serv ;
-
- /*
- * Get port number for listening to clients.
- */
- if( getservbyname( servInputName, NULL ) == NULL ||
- getservbyname( servOutputName, NULL ) == NULL )
- {
- postInfo( NULL, NULL,
- "Can't find one or more of the following udp services:"
- "\n\n `%s'\n `%s'\n\n"
- "To run over the network, you must have the following "
- "lines\n"
- "in your /etc/services file.\n\n"
- " %s %d/udp\n"
- " %s %d/udp\n\n"
- "Defaulting to listed ports.",
- servInputName, servOutputName,
- servInputName, VROOM_SERVER_INPUT_PORT,
- servOutputName, VROOM_CLIENT_INPUT_PORT ) ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Check to automatically end race if enough humans have finished.
- *----------------------------------------------------------------------------*/
- static void
- autoFinish(
- void
- )
- {
- int i ;
- int humansDone = 0 ;
- int robotsDone = 0 ;
- int totalDone ;
- float lastFinish = 0.0f ;
-
- /*
- * Go ahead and end if computer cars have finished at least
- * one lap and all human players have finished.
- */
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- if( cars[i].status & CAR_FINISHED )
- {
- if( isRobot[i] )
- {
- robotsDone++ ;
- }
- else
- {
- humansDone++ ;
- if( cars[i].finishTime > lastFinish )
- {
- lastFinish = cars[i].finishTime ;
- }
- }
- }
- }
- totalDone = robotsDone + humansDone ;
-
- /*
- * If all humans are done, then finish after 7 seconds of last
- * human finish.
- */
- if( humansDone == nPlayers && totalDone < MAX_PLAYERS )
- {
- if( currentTime - startTime - lastFinish > 7.0f )
- {
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- if( isRobot[i] && cars[i].lap > 0 &&
- ( cars[i].status & CAR_FINISHED ) == 0 )
- {
- autoFinishCar( i,
- currentTime - startTime ) ;
- racePacket.indTime[i] =
- cars[i].finishTime ;
- }
- }
- }
- }
- /*
- * If all but one human is done, give him 120 seconds after last
- * human finish to complete the race.
- */
- else if( nPlayers > 1 && totalDone == MAX_PLAYERS - 1 &&
- currentTime - startTime - lastFinish > 60.0f )
- {
- for( i = 0 ; i < MAX_PLAYERS ; i++ )
- {
- if( isRobot[i] == 0 && cars[i].lap > 0 &&
- ( cars[i].status & CAR_FINISHED ) == 0 )
- {
- autoFinishCar( i, currentTime - startTime ) ;
- racePacket.indTime[i] = cars[i].finishTime ;
- }
- }
- }
- }
-